#include <cstring>
#include <netdb.h>

#include "Script.h"
#include "../game/GameControl.h"
#include "../game/commands/GameCommand.h"
#include "../game/GameConf.h"
#include "../tools/Log.h"
#include "ControlSystem.h"

//A series of macros that make else if tests of strings convenient

#define CMD_TEST(cmd)  {\
static unsigned len = strlen(cmd); \
if(strncasecmp(in, cmd, len) == 0) {

#define CMD_END return; } }

#define CMD_ELSE_TEST(cmd) CMD_END \
CMD_TEST(cmd)

void Script::process(const char *in)
{
	if (strlen(in) == 0) return;	//You passed me garbage
	
	if(in[0] == ';')	// Interpret commands beginning with ;'s as commands issued to the current game instance
	{
		GameControl* g = GameControl::Instance();
		
		if (!g)
			lout << "There is no game currently running." << endl;
		
		else if(g->isPaused() && strcmp(in + 1, "resume") != 0)
		/*TODO				^ This is an evil hack
				Need to make resume events come through even if the game is paused
		*/
			lout << "Game is currently paused."<<endl;
		
		else {
			GameCommand* cmd = GameCommand::interpret(in + 1);
			
			if (!cmd)
				lout << "Unrecognized game command." << endl;
			else 
				g->appendGameCommand(cmd);
		}
		
		return;
	}
	
	/*	Load a series of commands from a file (each on a new line). The nth command will be issued n milliseconds
		into the game.
	*/
	CMD_TEST("load")
		
		char file_name[255];
		sscanf(in, "load %s", file_name);
		
		ifstream cmd_batch(file_name);
		
		if (!cmd_batch) {
			lout << "Unable to load file for script processing: " << cmd_batch << endl;
			return;
		}
		
		char line[255];
		unsigned cmd_timestamp = 1;		// Timestamp for first command (don't use 0)
		while (cmd_batch.getline(line, 255))
		{
			char cmd_with_timestamp[255];
			sprintf(cmd_with_timestamp, "%s %u", line, cmd_timestamp ++);
			process(cmd_with_timestamp);
		}
	
	CMD_ELSE_TEST("start single")
		ControlSystem::Instance().createGame(GameConf());
	
	CMD_ELSE_TEST("start multi")
		unsigned our_node_id;
		
		if (sscanf(in, "start multi %u", &our_node_id) != 1) {
			lout << "Error parsing node_id." << endl << "Usage: START MULTI [Node ID]" << endl;
			return;
		}
		
		ifstream network_config("conf/neighborhood.conf");
		
		if (!network_config) {
			lout << "Unable to open network config file." << endl;
			return;
		}
		
		GameConf cfg;
		cfg.network_conf = new NetworkConf();
		
		char line[255];
		while (network_config.getline(line, 255))
		{
			if (line[0] == '#') continue;
			
			char hostname[255];
			unsigned short node_id, port, is_host;
					
			NetworkPlayer *n = new NetworkPlayer();
			sscanf(line, "%hu %s %hu %hu", &node_id, hostname, &port, &is_host);
			
			bzero(&n->addr, sizeof(struct sockaddr_in));
			n->addr.sin_addr.s_addr = *((in_addr_t *)(gethostbyname(hostname))->h_addr);
			n->addr.sin_port = htons(port);
			n->addr.sin_family = AF_INET;
			
			if (our_node_id == node_id)		// We found ourselves
			{
				cfg.network_conf->me = n;
				if (is_host) cfg.network_conf->i_am_host = true;
			}
			
			cfg.network_conf->players.push_back(n);		// Add node to neighborhood
		}
		
		if (!cfg.network_conf->me) lout << "WARNING: Unable to find ourself in config file." << endl;
		
		ControlSystem::Instance().createGame(cfg);
	
	CMD_ELSE_TEST("exit")
		ControlSystem::Instance().exitApp();
	
	CMD_ELSE_TEST("quit")
		ControlSystem::Instance().exitApp();
	
	CMD_ELSE_TEST("end")
		ControlSystem::Instance().destroyGame();
	
	CMD_ELSE_TEST("menu to")
		char unused[64];
		char menuName[32];
		sscanf(in, "%s %s %s", unused, unused, menuName);
		string s(menuName);
		ControlSystem::Instance().changeGUIto(s);
	CMD_ELSE_TEST("menu disable")
		Game::Instance()->resumeGame();
		ControlSystem::Instance().disableGUI();
	CMD_END
}
